#include "stdafx.h"
#include "ui_layouts.h"

_SSL_BEGIN
_SSUIL_BEGIN

UILayout::UILayout()
{
	background_transparent_ = true;
	auto_width_by_ = kASByChilds;
	auto_height_by_ = kASByChilds;
	properties_ = 0;

	//
	ignore_invisible_controls_on_layout_ = true;
}

UILayout::~UILayout()
{

}

bool UILayout::ApplyAttributes(IUIBuilderInterface *ui_builder, 
	IUIXMLDocumentInterface *xml_document, UIXmlNode node)
{
	if(!__super::ApplyAttributes(ui_builder, xml_document, node))
		return false;

	UIXmlAttribute attribute = NULL;

	//
	attribute = xml_document->FirstAttribute(node,
		"ignore_invisible_controls_layout");
	if(attribute != NULL)
	{
		bool b = true;
		if(UIValueParseUtil::ParseBool(xml_document->AttributeValue(attribute), b) >= 1)
		{
			SetIgnoreInvisibleControlsOnLayout(b);
		}
	}

	return true;
}

void UILayout::SetIgnoreInvisibleControlsOnLayout(bool flag)
{
	ignore_invisible_controls_on_layout_ = flag;
	SetNeedUpdate(true);
}

UIHorizontalLayout::UIHorizontalLayout()
{
	childs_position_has_relation_ = true;

	//
}

UIHorizontalLayout::~UIHorizontalLayout()
{

}

void UIHorizontalLayout::OnRecalcChildsLayoutOnVisibleSizeChanged()
{
	// clear all the visibled child items
	visibled_child_items_.clear();
	if(visible_area_.Width() <= 0 || visible_area_.Height() <= 0)
	{
		return;
	}

	//
	UIRect client_rt(UIPoint(0,0), GetClientSize());
	UIRect visible_childs_rt = GetVisibleClientViewAreaInMyClient();

	// fetch the expand control and calc it's width
	IUIControlInterface *expand_control = NULL;
	int all_width = 0;
	for(IUIControlInterfaceAutoPtrs::iterator iter=child_items_.begin(); iter!=child_items_.end(); iter++)
	{
		IUIControlInterfaceAutoPtr &child = (*iter);
		SS_ASSERT(child.get() != NULL);
		if(!child->IsVisibled() && ignore_invisible_controls_on_layout_)
			continue;
		if(child->GetPresetHorzLayoutPositionType() == kLPExpand)
		{
			SS_ASSERT(expand_control == NULL);
			expand_control = child;
			continue;
		}

		if(!child->GetPresetPosition().HasWidth())
		{
			SS_ASSERT(expand_control == NULL);
			expand_control = child;
			continue;
		}
		all_width += child->GetWidth();
	}

	int expand_control_width = 0;
	if(expand_control != NULL && all_width < client_rt.Width())
	{
		expand_control_width = client_rt.Width() - all_width;
	}

	// find the first visibled item
	int xoffset = 0;
	IUIControlInterfaceAutoPtrs::iterator iter=child_items_.begin();
	for(; iter!=child_items_.end(); iter++)
	{
		IUIControlInterfaceAutoPtr &child = (*iter);
		SS_ASSERT(child.get() != NULL);
		if(!child->IsVisibled() && ignore_invisible_controls_on_layout_)
			continue;
		int control_width = 0;
		if(child == expand_control)
		{
			control_width = expand_control_width;
		}else
		{
			SS_ASSERT(child->GetPresetPosition().HasWidth());
			control_width = child->GetWidth();
		}
		if(xoffset + control_width > visible_childs_rt.left)
			break;
		xoffset += control_width;
	}

	SS_ASSERT(iter != child_items_.end());

	//
	IUIControlInterface *child = (*iter).get();
	SetItemPosition(child, xoffset, client_rt, expand_control, expand_control_width);

	iter++;
	IUIControlInterfaceAutoPtrs::iterator iter_end = iter;
	for(; iter_end!=child_items_.end(); iter_end++)
	{
		IUIControlInterfaceAutoPtr &child = (*iter_end);
		SS_ASSERT(child.get() != NULL);
		if(!child->IsVisibled() && ignore_invisible_controls_on_layout_)
			continue;
		SetItemPosition(child, xoffset, client_rt, expand_control, expand_control_width);
		if(xoffset >= visible_childs_rt.right)
			break;
	}
}

UIRect UIHorizontalLayout::GetChildsRect()
{
	UIRect rt;

	for(IUIControlInterfaceAutoPtrs::iterator iter=child_items_.begin(); iter!=child_items_.end(); iter++)
	{
		IUIControlInterface *child = *iter;
		if(child == NULL)
			continue;
		if(!child->IsVisibled() && ignore_invisible_controls_on_layout_)
			continue;

		UIRect rt_calced;
		if(!child->GetPresetPosition().GetPosition(0, 0, rt_calced, dynamic_cast<IUIAutoSizeInterface*>(child)))
			continue;
		rt.right += rt_calced.Width();
		if(rt.top < rt_calced.top)
			rt.top = rt_calced.top;
		if(rt.bottom < rt_calced.bottom)
			rt.bottom = rt_calced.bottom;
	}
	rt.Inflate(client_borders_);
	rt.left = 0;
	rt.top = 0;
	return rt;
}

void UIHorizontalLayout::SetItemPosition(
	IUIControlInterface *item,
	int &xoffset,
	const UIRect &client_rt,
	IUIControlInterface *expand_control,
	int expand_control_width
	)
{
	UIRect control_rt;
	item->GetPresetPosition().GetPosition(client_rt,
		control_rt, dynamic_cast<IUIAutoSizeInterface*>(item));
	if(item == expand_control)
		control_rt.right = control_rt.left + expand_control_width;

	UIRect control_rt_fix;
	control_rt_fix.left = xoffset;
	control_rt_fix.right = xoffset + control_rt.Width();
	switch(item->GetPresetVertLayoutPositionType())
	{
	case kLPNear:
		control_rt_fix.top = client_rt.top;
		control_rt_fix.bottom = control_rt_fix.top + control_rt.Height();
		break;
	case kLPExpand:
	case kLPCenter:
		control_rt_fix.top = (client_rt.Height() - control_rt.Height()) / 2;
		control_rt_fix.bottom = control_rt_fix.top + control_rt.Height();
		break;
	case kLPFar:
		control_rt_fix.bottom = client_rt.bottom;
		control_rt_fix.top = control_rt_fix.bottom - control_rt.Height();
		break;
	case kLPFree:
		control_rt_fix.top = control_rt.top;
		control_rt_fix.bottom = control_rt.bottom;
		break;
	}
	item->SetPosition(control_rt_fix, client_rt);
	visibled_child_items_.push_back(item);
	xoffset += control_rt.Width();
}

UIVerticalLayout::UIVerticalLayout()
{
	childs_position_has_relation_ = true;

	//
}

UIVerticalLayout::~UIVerticalLayout()
{

}

void UIVerticalLayout::OnRecalcChildsLayoutOnVisibleSizeChanged()
{
	// clear all the visibled child items
	visibled_child_items_.clear();
	if(visible_area_.Width() <= 0 || visible_area_.Height() <= 0)
	{
		return;
	}

	//
	UIRect client_rt(UIPoint(0,0), GetClientSize());
	UIRect visible_childs_rt = GetVisibleClientViewAreaInMyClient();

	// fetch the expand control and calc it's width
	IUIControlInterface *expand_control = NULL;
	int all_height = 0;
	for(IUIControlInterfaceAutoPtrs::iterator iter=child_items_.begin(); iter!=child_items_.end(); iter++)
	{
		IUIControlInterfaceAutoPtr &child = (*iter);
		SS_ASSERT(child.get() != NULL);
		if(!child->IsVisibled() && ignore_invisible_controls_on_layout_)
			continue;
		if(child->GetPresetVertLayoutPositionType() == kLPExpand)
		{
			SS_ASSERT(expand_control == NULL);
			expand_control = child;
			continue;
		}

		if(!child->GetPresetPosition().HasHeight())
		{
			SS_ASSERT(expand_control == NULL);
			expand_control = child;
			continue;
		}
		all_height += child->GetHeight();
	}

	int expand_control_height = 0;
	if(expand_control != NULL && all_height < client_rt.Height())
	{
		expand_control_height = client_rt.Height() - all_height;
	}

	// find the first visibled item
	int yoffset = 0;
	IUIControlInterfaceAutoPtrs::iterator iter=child_items_.begin();
	for(; iter!=child_items_.end(); iter++)
	{
		IUIControlInterfaceAutoPtr &child = (*iter);
		SS_ASSERT(child.get() != NULL);
		if(!child->IsVisibled() && ignore_invisible_controls_on_layout_)
			continue;
		int control_height = 0;
		if(child == expand_control)
		{
			control_height = expand_control_height;
		}else
		{
			SS_ASSERT(child->GetPresetPosition().HasHeight());
			control_height = child->GetHeight();
		}
		if(yoffset + control_height > visible_childs_rt.top)
			break;
		yoffset += control_height;
	}

	SS_ASSERT(iter != child_items_.end());

	//
	IUIControlInterface *child = (*iter).get();
	SetItemPosition(child, yoffset, client_rt, expand_control, expand_control_height);

	iter++;
	IUIControlInterfaceAutoPtrs::iterator iter_end = iter;
	for(; iter_end!=child_items_.end(); iter_end++)
	{
		IUIControlInterfaceAutoPtr &child = (*iter_end);
		SS_ASSERT(child.get() != NULL);
		if(!child->IsVisibled() && ignore_invisible_controls_on_layout_)
			continue;
		SetItemPosition(child, yoffset, client_rt, expand_control, expand_control_height);
		if(yoffset >= visible_childs_rt.bottom)
			break;
	}
}

UIRect UIVerticalLayout::GetChildsRect()
{
	UIRect rt;

	for(IUIControlInterfaceAutoPtrs::iterator iter=child_items_.begin(); iter!=child_items_.end(); iter++)
	{
		IUIControlInterface *child = *iter;
		if(child == NULL)
			continue;
		if(!child->IsVisibled() && ignore_invisible_controls_on_layout_)
			continue;

		UIRect rt_calced;
		if(!child->GetPresetPosition().GetPosition(0, 0, rt_calced, dynamic_cast<IUIAutoSizeInterface*>(child)))
			continue;
		rt.bottom += rt_calced.Height();
		if(rt.left < rt_calced.left)
			rt.left = rt_calced.left;
		if(rt.right < rt_calced.right)
			rt.right = rt_calced.right;
	}
	rt.Inflate(client_borders_);
	rt.left = 0;
	rt.top = 0;
	return rt;
}

void UIVerticalLayout::SetItemPosition(
	IUIControlInterface *item,
	int &yoffset,
	const UIRect &client_rt,
	IUIControlInterface *expand_control,
	int expand_control_height
	)
{
	UIRect control_rt;
	item->GetPresetPosition().GetPosition(client_rt,
		control_rt, dynamic_cast<IUIAutoSizeInterface*>(item));
	if(item == expand_control)
		control_rt.bottom = control_rt.top + expand_control_height;

	UIRect control_rt_fix;
	control_rt_fix.top = yoffset;
	control_rt_fix.bottom = yoffset + control_rt.Height();
	switch(item->GetPresetHorzLayoutPositionType())
	{
	case kLPNear:
		control_rt_fix.left = client_rt.left;
		control_rt_fix.right = control_rt_fix.left + control_rt.Width();
		break;
	case kLPExpand:
	case kLPCenter:
		control_rt_fix.left = (client_rt.Width() - control_rt.Width()) / 2;
		control_rt_fix.right = control_rt_fix.left + control_rt.Width();
		break;
	case kLPFar:
		control_rt_fix.right = client_rt.right;
		control_rt_fix.left = control_rt_fix.right - control_rt.Width();
		break;
	case kLPFree:
		control_rt_fix.left = control_rt.left;
		control_rt_fix.right = control_rt.right;
		break;
	}
	item->SetPosition(control_rt_fix, client_rt);
	visibled_child_items_.push_back(item);
	yoffset += control_rt.Height();
}

UIFlowLayout::UIFlowLayout()
{
	childs_position_has_relation_ = true;

	//
}

UIFlowLayout::~UIFlowLayout()
{

}

void UIFlowLayout::OnRecalcChildsLayoutOnVisibleSizeChanged()
{
	// clear all the visibled child items
	visibled_child_items_.clear();
	if(visible_area_.Width() <= 0 || visible_area_.Height() <= 0)
	{
		return;
	}

	UIRect client_rt(UIPoint(0,0), GetClientSize());
	UIRect visible_childs_rt = GetVisibleClientViewAreaInMyClient();

	int yoffset = 0;
	int index_b = 0, index_e = 0;

	while(index_b < (int)child_items_.size())
	{
		if(yoffset >= visible_childs_rt.bottom)
			break;
		int row_height = 0;
		if(!CalcALine(client_rt.Width(), row_height, index_b, index_e))
			break;
		if(index_b == index_e)
			break;
		if(yoffset + row_height > visible_childs_rt.top)
		{
			int xoffset = 0;
			for(int i=index_b; i<index_e; i++)
			{
				IUIControlInterface *control = child_items_[i];
				SS_ASSERT(control != NULL);
				if(xoffset >= visible_childs_rt.right)
					break;
				if(xoffset + control->GetWidth() > visible_childs_rt.left)
				{
					UIRect control_rt;
					control_rt.left = xoffset;
					control_rt.right = control_rt.left + control->GetWidth();
					switch(control->GetPresetVertLayoutPositionType())
					{
					case kLPNear:
						control_rt.top = yoffset;
						control_rt.bottom = control_rt.top + control->GetHeight();
						break;
					case kLPFar:
						control_rt.bottom = yoffset + row_height;
						control_rt.top = control_rt.bottom - control->GetHeight();
						break;
					case kLPExpand:
					case kLPCenter:
					case kLPFree:
					default:
						control_rt.top = yoffset + (row_height - control->GetHeight()) / 2;
						control_rt.bottom = control_rt.top + control->GetHeight();
						break;
					}
					control->SetPosition(control_rt, client_rt);
					visibled_child_items_.push_back(control);
				}
				xoffset += control->GetWidth();
			}
		}

		index_b = index_e;
		yoffset += row_height;
	}

}


bool UIFlowLayout::CalcALine(
	ss_in_ int width,
	ss_out_ int &height,
	ss_in_ int index_b,
	ss_out_ int &index_e
	)
{
	if(width <= 0)
		return false;

	if(index_b < 0 || index_b >= (int)child_items_.size())
		return false;

	height = 0;

	int xoffset = 0;

	index_e = index_b;
	for(; xoffset<width && index_e<(int)child_items_.size(); index_e++)
	{
		IUIControlInterface *control = child_items_[index_e];
		SS_ASSERT(control != NULL);
		SS_ASSERT(control->GetPresetPosition().HasWidth() && control->GetPresetPosition().HasHeight());
		if(xoffset + control->GetWidth() > width)
		{
			if(xoffset > 0)
				break;
		}
		xoffset += control->GetWidth();
		if(height < control->GetHeight())
			height = control->GetHeight();
	}
	return true;
}

_SSUIL_END
_SSL_END
